package com.djc.exam.webapp.base.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @version V1.0.0
 * @description:
 * @date 2020/12/29 14:31
 */
@Slf4j
public class TimeUtilCustomize {

    public static final String DATE_TIME_FORMAT= "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_TIME_FORMAT_H= "yyyy-MM-dd HH:00:00";
    public static final String DATE_DAY_FORMAT = "yyyy-MM-dd";
    public static final String DATE_MONTH_FORMAT = "yyyy-MM";
    public static final String DATE_YEAR_FORMAT = "yyyy";
    public static final String DATE_DD_FORMAT = "dd";
    public static final String DATE_YMD_FORMAT = "yyyyMMdd";
    public static final String DATE_YM_FORMAT = "yyyyMM";
    public static final String DATE_MD_FORMAT = "MM-dd";
    public static final String DATE_MD_ZH = "MM月dd日";

    private static TimeUtilCustomize instance = new TimeUtilCustomize();
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    private TimeUtilCustomize() {
    }

    public static TimeUtilCustomize getInstance() {
        return instance;
    }

    public static String parseDateToStr(String formatDate, Date date) {
        SimpleDateFormat format = new SimpleDateFormat(formatDate);
        return format.format(date);
    }

    public static String parseLocalDateToStr(String formatDate, LocalDateTime localDateTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(formatDate);
        String localTime = df.format(localDateTime);
        return localTime;
    }

    public static Date parseStrToDate(String formatDate, String date) {
        SimpleDateFormat format = new SimpleDateFormat(formatDate);
        Date dateN = new Date();
        try {
            dateN = format.parse(date);
        } catch (ParseException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return dateN;
    }

    public static Date parseDateToDateFormat(String formatDate, Date date) {
        SimpleDateFormat format = new SimpleDateFormat(formatDate);
        String f = format.format(date);
        Date dateN = new Date();
        try {
            dateN = format.parse(f);
        } catch (ParseException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return dateN;
    }

    // 获取日期 “xx月xx日”
    public static String toMonthDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int day = c.get(Calendar.DAY_OF_MONTH);

        int hour = c.get(Calendar.HOUR);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
        int dayweek = c.get(Calendar.DAY_OF_WEEK);
        String dayweek2 = dayweek == 0 ? "日" : dayweek + "";
        String monthDay = null;
        if (month< 10){
            if (day <10){
                monthDay =  "0"+month + "月0" + day + "日";
            }else {
                monthDay =  "0"+month + "月" + day + "日";
            }
        }else {
            if (day <10){
                monthDay =  month + "月0" + day + "日";
            }else {
                monthDay =  month + "月" + day + "日";
            }
        }
        return monthDay;
    }

    // 获取日期 “xxxx年xx月”
    public static String toYearMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int day = c.get(Calendar.DAY_OF_MONTH);

        int hour = c.get(Calendar.HOUR);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
        int dayweek = c.get(Calendar.DAY_OF_WEEK);
        String dayweek2 = dayweek == 0 ? "日" : dayweek + "";
        String yearMonth = null;
        if (month< 10){
            yearMonth =  year + "年0" + month + "月";
        }else {
            yearMonth =  year + "年" + month + "月";
        }
        return yearMonth;
    }

    // 获取时间“xx”
    public static Integer toHour(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int day = c.get(Calendar.DAY_OF_MONTH);

        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
        int dayweek = c.get(Calendar.DAY_OF_WEEK);
        String dayweek2 = dayweek == 0 ? "日" : dayweek + "";
        return hour;
    }

    /**
     * 获取时间“xx日xx时”
     *
     * @param date
     * @return
     */
    public static String toHourStr(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        SimpleDateFormat sdf = new SimpleDateFormat("dd日HH时");
        return sdf.format(c.getTime());
    }

    /**
     * 获取当前日期是本周第几天
     * @param date
     * @return
     */
    public static Integer getWeekDayNo(Date date){
        Calendar cal = Calendar.getInstance();
        //设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        //获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        return dayWeek-1;
    }

    /**
     * 获取当前输入时间所在月份的所有 天
     *
     * @return
     */
    public static List<String> getDaysOfNowMonth() {
        List<String> monthDayList = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat("d");
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        //获取当月最后一天
        Integer last = Integer.parseInt(format.format(ca.getTime()));
        for (int i = 1; i <= last; i++) {
            monthDayList.add(i + "");
        }
        return monthDayList;
    }

    /**
     * 获取当前输入时间所在月份的所有日期
     *
     * @return
     */
    public static Map<String, Date> getDateOfNowMonth() {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        Map<String, Date> dateMap = new HashMap<>();
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));


        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);

        try {
            //第一天
            String firstDateStr = simpleDateFormat.format(c.getTime());
            Date firstDate = simpleDateFormat.parse(firstDateStr);
            //最后一天
            String lastDateStr = simpleDateFormat.format(ca.getTime());
            Date lastDate = simpleDateFormat.parse(lastDateStr);

            dateMap.put("firstDay", firstDate);
            dateMap.put("lastDay", lastDate);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return dateMap;
    }

    /**
     * 获取今日前number日的日期
     *
     * @param number
     * @return
     */
    public static Date getDayFromToday(Integer number) {
        try {

            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DAY_OF_YEAR, -number);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String date = simpleDateFormat.format(c.getTime());
            return simpleDateFormat.parse(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取今日的日期
     *
     * @return
     */
    public static Date getDayToday() {
        try {
            Date date = new Date();
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(Calendar.DAY_OF_MONTH, 1);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = simpleDateFormat.format(c.getTime());
            return simpleDateFormat.parse(dateStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<String> getMonthDayList() {
        List<String> dayList = new ArrayList<>();
        dayList.add("7");
        dayList.add("14");
        dayList.add("21");
        dayList.add("28");
        return dayList;
    }

    /**
     * 返回两个时间之间相差多少天
     *
     * @param now
     * @param past
     * @return
     */
    public static Integer dayNumberBetweenToDate(Date now, Date past) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String pastString = simpleDateFormat.format(past);
            Date pastDate = simpleDateFormat.parse(pastString);
            return (int) (((now.getTime() - pastDate.getTime()) / (1000 * 3600 * 24)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回两个时间之间相差多少个月
     *
     * @param now
     * @param past
     * @return
     */
    public static Integer monthNumberBetweenToDate(Date now, Date past) {
        try {
            Calendar bef = Calendar.getInstance();
            Calendar aft = Calendar.getInstance();
            bef.setTime(past);
            aft.setTime(now);
            int result = aft.get(Calendar.MONTH) - bef.get(Calendar.MONTH);
            int month = (aft.get(Calendar.YEAR) - bef.get(Calendar.YEAR)) * 12;
            return Math.abs(month + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取近一年的月份
     */
    public static List<String> getFullYearList(String pattern) {
        if (StringUtils.isBlank(pattern)) {
            pattern = "yyyyMM";
        }
        try {
            SimpleDateFormat fod = new SimpleDateFormat(pattern);
            Calendar calc = Calendar.getInstance();
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 12; i++) {
                calc.setTime(new Date());
                calc.add(Calendar.MONTH, -i);
                Date minDate = calc.getTime();
                list.add(fod.format(minDate));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取近30天的日期
     */
    public static List<String> getDayList() {
        try {
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMMdd");
            Calendar calc = Calendar.getInstance();
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 30; i++) {
                calc.setTime(new Date());
                calc.add(Calendar.DATE, -i);
                Date minDate = calc.getTime();
                list.add(fod.format(minDate));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取最近7天的日期
     */
    public static List<String> get7DayList() {
        try {
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMMdd");
            Calendar calc = Calendar.getInstance();
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 7; i++) {
                calc.setTime(new Date());
                calc.add(Calendar.DATE, i-6);
                Date minDate = calc.getTime();
                list.add(fod.format(minDate));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取最近7天的日期
     */
    public static List<Date> get7DayDateList() {
        try {
            Calendar calc = Calendar.getInstance();
            List<Date> list = new ArrayList<>();
            for (int i = 0; i < 7; i++) {
                calc.setTime(new Date());
                calc.add(Calendar.DATE, i-6);
                Date minDate = calc.getTime();
                list.add(minDate);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取前一天日期
     */
    public static String getDayBefore(String date) {
        try {
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMMdd");
            Calendar calc = Calendar.getInstance();
            calc.setTime(fod.parse(date));
            calc.add(Calendar.DATE, -1);
            Date minDate = calc.getTime();
            String strDate = fod.format(minDate);
            return strDate;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前时间后几小时（nHour为正），前几小时（nHour为负）
     */
    public static Date getBeforeOrAfterHour(int nHour) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.HOUR_OF_DAY, nHour);
            return calendar.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前时间后几天时间（nDay为正），前几天时间（nDay为负）
     */
    public static Date getBeforeOrAfterDay(int nDay) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.DAY_OF_MONTH, nDay);
            return calendar.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前时间后几个月时间（nDay为正），前几个月时间（nDay为负）
     */
    public static Date getBeforeOrAfterMonth(int nMonth) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.MONTH, nMonth);
            return calendar.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取某个日期前后月份，正后，负前
     */
    public static Date getSomeDateOfMonth(Date date,int nMonth) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.MONTH, nMonth);
            return calendar.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取某个日期前后年份
     */
    public static Date getSomeDateOfYear(Date date,int nYear) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.YEAR, nYear);
            return calendar.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取两个时间段内的各个时间（天）
     */
    public static List<String> getDatesInTwoTimePeriods(Date now, Date past) {
        try {
            Integer days = TimeUtilCustomize.dayNumberBetweenToDate(now, past);
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMMdd");
            Calendar calc = Calendar.getInstance();
            List<String> list = new ArrayList<>();
            for (int i = 0; i <= days; i++) {
                calc.setTime(now);
                calc.add(Calendar.DATE, -(days - i));
                Date minDate = calc.getTime();
                list.add(fod.format(minDate));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取两个时间段内的各个月份
     */
    public static List<String> getMonthsInTwoTimePeriods(Date now, Date past) {
        try {
            Integer months = TimeUtilCustomize.monthNumberBetweenToDate(now, past);
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMM");
            Calendar calc = Calendar.getInstance();
            List<String> list = new ArrayList<>();
            for (int i = 0; i <= months; i++) {
                calc.setTime(now);
                calc.add(Calendar.MONTH, -(months-i));
                Date minDate = calc.getTime();
                list.add(fod.format(minDate));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取前一月日期
     */
    public static String getMonthBefore(String date) {
        try {
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMM");
            Calendar calc = Calendar.getInstance();
            calc.setTime(fod.parse(date));
            calc.add(Calendar.MONTH, -1);
            Date minDate = calc.getTime();
            String strDate = fod.format(minDate);
            return strDate;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取前一年同月日期
     */
    public static String getMonthBeforeYear(String date) {
        try {
            SimpleDateFormat fod = new SimpleDateFormat("yyyyMM");
            Calendar calc = Calendar.getInstance();
            calc.setTime(fod.parse(date));
            calc.add(Calendar.MONTH, -12);
            Date minDate = calc.getTime();
            String strDate = fod.format(minDate);
            return strDate;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取给定时间后一天时间
     */
    public static Date getAfterDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        date = calendar.getTime();
        return date;
    }

    /**
     * 获取给定时间前后给定时间(正为后推，负为前推)
     */
    public static Date getSomeDateOfDay(Date date,Integer days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, days);
        date = calendar.getTime();
        return date;
    }

    /**
     * 时间小时加减
     *
     * @param hour 小时数
     * @return time difference;
     */
    public static Date hourDifference(Date date, int hour) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, hour);// 24小时制
        date = cal.getTime();
        return date;

    }

    /**
     * 给时间加上几分钟
     *
     * @param minute 需要加的时间
     * @return
     */
    public static Date minuteDifference(Date date, int minute) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, minute);// 24小时制
        date = cal.getTime();
        return date;

    }

    /**
     * 获取某个时间的前(后)n个小时时间段(n为正数时获取后n个小时，n为负数时获取前n个小时)
     * @param date
     * @param n
     * @return
     */
    public static List<String> getHours(Date date, int n) {
        List<String> hours = new ArrayList<>();
        if (n< 0){
            int j = -n;
            for (int i=1;i<=j;i++){
                Calendar calendar  = Calendar.getInstance();
                calendar .setTime(date);
                calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - (j-i));
                String hour = calendar.get(Calendar.HOUR_OF_DAY)+":00";
                hours.add(hour);
            }
        }
        if (n> 0){
            for (int i=1;i<=n;i++){
                Calendar calendar  = Calendar.getInstance();
                calendar .setTime(date);
                calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + i);
                String hour = calendar.get(Calendar.HOUR_OF_DAY)+":00";
                hours.add(hour);
            }
        }

        return hours;
    }

    /**
     * 获取一天24小时各个时间段
     * @return
     */
    public static List<String> getHourList() {
        List<String> hours = new ArrayList<>();
        for (int i=0; i<=23;i++){
            hours.add(i+":00");
        }
        return hours;
    }

    /**
     * 获取某个日期月的头一天
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        // 设置月份
        cal.setTime(date);
        // 获取某月最小天数
        int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        // 格式化日期
        Date time = cal.getTime();
        return time;
    }

    /**
     * 获取某个日期年的头一天
     * @param date
     * @return
     */
    public static Date getFirstDayOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        // 设置月份
        cal.setTime(date);
        // 获取某月最小天数
        int firstDay = cal.getActualMinimum(Calendar.DAY_OF_YEAR);
        // 设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_YEAR, firstDay);
        // 格式化日期
        Date time = cal.getTime();
        return time;
    }

    /**
     * 获取某年的当前时间（year为正是当前时间往后。year为负，当前时间往前）
     * @param year
     * @return
     */
    public static Date getSomeYearCurrentDateBy(int year){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        //当前时间加减减年数，即某年前的时间
        calendar.add(Calendar.YEAR, year);
        //获取一年前的时间，或者一个月前的时间
        return calendar.getTime();
    }


}
